package com.hmy.finance.service.receipt.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.hmy.ccp.common.dto.ContextUserInfo;
import com.hmy.ccp.error.exception.HMYRuntimeException;
import com.hmy.ccp.starter.web.utils.UserContextUtil;
import com.hmy.finance.api.bo.core.request.enums.ReceiptOffsetBillStatusEnum;
import com.hmy.finance.api.bo.core.request.receiptOffset.ReceiptOffsetAuditRequest;
import com.hmy.finance.api.bo.core.request.receiptOffset.ReceiptOffsetCancelRequest;
import com.hmy.finance.api.bo.core.request.receiptOffset.ReceiptOffsetRetractRequest;
import com.hmy.finance.api.bo.core.request.receiptOffset.ReceiptOffsetRevokeRequest;
import com.hmy.finance.api.bo.core.response.receiptOffset.ReceiptOffsetAuditResponse;
import com.hmy.finance.api.bo.core.response.receiptOffset.ReceiptOffsetCancelResponse;
import com.hmy.finance.api.bo.core.response.receiptOffset.ReceiptOffsetRetractResponse;
import com.hmy.finance.api.bo.core.response.receiptOffset.ReceiptOffsetRevokeResponse;
import com.hmy.finance.api.enums.ReceiptOffsetApprovalNodeEnum;
import com.hmy.finance.common.constants.ReceiptOffsetStatusConstant;
import com.hmy.finance.dal.mapper.ReceivableInventoryMapper;
import com.hmy.finance.dal.mapper.receipt.ReceiptContractApportionRecordMapper;
import com.hmy.finance.dal.mapper.receipt.ReceiptOffsetBillMapper;
import com.hmy.finance.dal.po.ReceivableInventoryPo;
import com.hmy.finance.dal.po.receipt.ReceiptContractApportionRecordPo;
import com.hmy.finance.dal.po.receipt.ReceiptOffsetBillPo;
import com.hmy.finance.manager.workflow.FlowProcessClientManager;
import com.hmy.finance.manager.workflow.FlowTaskClientManager;
import com.hmy.finance.service.receipt.ReceiptOffsetApprovalService;
import com.hmy.finance.service.receipt.ReceiptOffsetBillService;
import com.hmy.finance.service.receipt.dto.ReceiptOffsetAduitDto;
import com.hmy.finance.service.receipt.dto.ReceiptOffsetCancelDto;
import com.hmy.finance.service.receipt.dto.ReceiptOffsetRevokeDto;

import com.hmy.finance.service.receipt.dto.receiptOffset.ReceiptBillOffsetHandlerDto;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
public class ReceiptOffsetApprovalServiceImpl implements ReceiptOffsetApprovalService {

    @Resource
    private ReceiptOffsetBillMapper receiptOffsetBillMapper;

    @Resource
    private ReceiptContractApportionRecordMapper receiptContractApportionRecordMapper;

    @Resource
    private ReceivableInventoryMapper receivableInventoryMapper;

    @Resource
    private FlowProcessClientManager flowProcessClientManager;

    @Resource
    private FlowTaskClientManager flowTaskClientManager;

    @Resource
    private ReceiptOffsetBillService receiptOffsetBillService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReceiptOffsetRevokeResponse revokeReceiptOffset(ReceiptOffsetRevokeRequest receiptOffsetRevokeRequest) {
        //参数转换
        ReceiptOffsetRevokeDto revokeDto = ReceiptOffsetRevokeDto.convertToDto(receiptOffsetRevokeRequest);

        //查询核销单
        ReceiptOffsetBillPo receiptOffset = getOneReceiptOffset(revokeDto.getReceiptOffsetBillId());
        revokeDto.setReceiptOffsetBillPo(receiptOffset);

        //判断核销单是否存在
        if (Objects.isNull(receiptOffset)) {
            throw new HMYRuntimeException(506800001);
        }

        //判断状态是否可以撤销
//        if (!ReceiptOffsetStatusConstant.BILL_STATUS_CAN_REVOKED.contains(receiptOffset.getBillStatus())) {
//            throw new HMYRuntimeException(506900003);
//        }

        //更新主单状态为'撤销状态'
        ReceiptOffsetBillStatusEnum toRevokeBillStatusEnum = getToRevokeBillStatusEnum(revokeDto);
        updateReceiptOffsetBillStatusById(receiptOffset, toRevokeBillStatusEnum, 506900004);

        //撤销流程
        flowProcessClientManager.revoke(revokeDto.buildRevokeProcessRequest(toRevokeBillStatusEnum));

        ReceiptOffsetRevokeResponse resp = new ReceiptOffsetRevokeResponse();
        resp.setReceiptOffsetBillId(receiptOffset.getReceiptOffsetBillId());
        resp.setSuccess(Boolean.TRUE);
        return resp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReceiptOffsetCancelResponse cancelReceiptOffset(ReceiptOffsetCancelRequest receiptOffsetCancelRequest) {
        //参数转换
        ReceiptOffsetCancelDto cancelDto = ReceiptOffsetCancelDto.convertToDto(receiptOffsetCancelRequest);

        //查询核销单
        ReceiptOffsetBillPo receiptOffset = getOneReceiptOffset(cancelDto.getReceiptOffsetBillId());
        cancelDto.setReceiptOffsetBillPo(receiptOffset);

        //判断核销单是否存在
        if (Objects.isNull(receiptOffset)) {
            throw new HMYRuntimeException(506800001);
        }

        //判断状态是否可以作废
        if (!ReceiptOffsetStatusConstant.BILL_STATUS_CAN_CANCEL.contains(receiptOffset.getBillStatus())) {
            throw new HMYRuntimeException(506900005);
        }

        //更新主单状态为'作废状态'
        updateReceiptOffsetBillStatusById(receiptOffset, cancelDto.getTargetStatus(), 506900006);

        //作废流程
        flowProcessClientManager.removeProcessInstance(receiptOffset.getProcessInstanceId(), cancelDto.buildCancelProcessRequest());

        ReceiptOffsetCancelResponse resp = new ReceiptOffsetCancelResponse();
        resp.setReceiptOffsetBillId(receiptOffset.getReceiptOffsetBillId());
        resp.setSuccess(Boolean.TRUE);
        return resp;
    }

    @Override
    public ReceiptOffsetAuditResponse auditReceiptOffset(ReceiptOffsetAuditRequest receiptOffsetAuditRequest) {
        log.info("auditReceiptOffset user:{} ,params:{}", JSON.toJSONString(UserContextUtil.getCurrentUser()), JSON.toJSONString(receiptOffsetAuditRequest));
        //参数转换
        ReceiptOffsetAduitDto aduitDto = ReceiptOffsetAduitDto.convertToDto(receiptOffsetAuditRequest);

        //查询核销单
        ReceiptOffsetBillPo receiptOffset = getOneReceiptOffset(aduitDto.getReceiptOffsetBillId());
        aduitDto.setReceiptOffsetBillPo(receiptOffset);

        //判断核销单是否存在
        if (Objects.isNull(receiptOffset)) {
            throw new HMYRuntimeException(506800001);
        }
        //判断状态是否可以审核
        if (!ReceiptOffsetStatusConstant.BILL_STATUS_CAN_APPROVE_ING.contains(receiptOffset.getBillStatus())) {
            throw new HMYRuntimeException(506900007);
        }

        //更新主单状态为'审核状态'
        ReceiptOffsetBillStatusEnum toBillStatusEnum = getToBillStatusEnum(aduitDto);

        //审批流程
        flowTaskClientManager.complete(aduitDto.buildCompleteRequest(toBillStatusEnum));

        //判断是否是最后审批流程节点-审批通过
        if (toBillStatusEnum.equals(ReceiptOffsetBillStatusEnum.APPROVE_PASS)) {
            LambdaQueryWrapper<ReceiptContractApportionRecordPo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ReceiptContractApportionRecordPo::getIsDeleted, 0);
            queryWrapper.eq(ReceiptContractApportionRecordPo::getReceiptOffsetBillId, receiptOffset.getReceiptOffsetBillId());
            List<ReceiptContractApportionRecordPo> recordPos = receiptContractApportionRecordMapper.selectList(queryWrapper);
            List<Long> contractIds = recordPos.stream().map(ReceiptContractApportionRecordPo::getContractId).distinct().collect(Collectors.toList());
            LambdaQueryWrapper<ReceivableInventoryPo> updateWrapper = new LambdaQueryWrapper<>();
            updateWrapper.eq(ReceivableInventoryPo::getIsDeleted, 0);
            updateWrapper.in(ReceivableInventoryPo::getContractId, contractIds);
            ReceivableInventoryPo receivableInventoryPo = new ReceivableInventoryPo();
            receivableInventoryPo.setLastReceivedTime(LocalDateTime.now());
            receivableInventoryMapper.update(receivableInventoryPo, updateWrapper);

            //审批通过后续流程
            try {
                ReceiptBillOffsetHandlerDto receiptBillOffsetHandlerDto = BeanUtil.copyProperties(receiptOffset, ReceiptBillOffsetHandlerDto.class);
                Boolean flag = receiptOffsetBillService.doReceiptBillOffsetHandler(receiptBillOffsetHandlerDto);
                if (Boolean.FALSE.equals(flag)) {
                    log.info("auditReceiptOffset 核销失败 params:{}", JSON.toJSONString(receiptBillOffsetHandlerDto));
                    toBillStatusEnum = ReceiptOffsetBillStatusEnum.OFFSET_FAILED;
                } else {
                    log.info("auditReceiptOffset 核销成功 params:{}", JSON.toJSONString(receiptBillOffsetHandlerDto));
                    toBillStatusEnum = ReceiptOffsetBillStatusEnum.OFFSET_SUCCESS;
                }
            } catch (Exception e) {
                log.error("ReceiptOffsetBillServiceImp doReceiptBillOffsetHandler error", e);
            }
        }
        updateReceiptOffsetBillStatusById(receiptOffset, toBillStatusEnum, 506900008);

        ReceiptOffsetAuditResponse resp = new ReceiptOffsetAuditResponse();
        resp.setReceiptOffsetBillId(receiptOffset.getReceiptOffsetBillId());
        resp.setSuccess(Boolean.TRUE);
        return resp;
    }

    @Override
    public ReceiptOffsetRetractResponse retractReceiptOffset(ReceiptOffsetRetractRequest receiptOffsetRetractRequest) {
        return null;
    }

    @Override
    public void createReceiptOffset(Object receiptOffsetFlowCreateDto) {

    }

    @Override
    public void submitReceiptOffset(Object receiptOffsetFlowSubmitDto) {

    }

    /**
     * 根据核销单id查询核销主单信息
     *
     * @param receiptOffsetBillId
     * @return
     */
    private ReceiptOffsetBillPo getOneReceiptOffset(Long receiptOffsetBillId) {
        LambdaQueryWrapper<ReceiptOffsetBillPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffsetBillId);
        queryWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        return receiptOffsetBillMapper.selectOne(queryWrapper);
    }

    /**
     * 根据主键Id更新核销单状态
     *
     * @param receiptOffset
     */
    private void updateReceiptOffsetBillStatusById(ReceiptOffsetBillPo receiptOffset, ReceiptOffsetBillStatusEnum receiptOffsetBillStatusEnum, Integer msgCode) {
        ReceiptOffsetBillPo updatePo = new ReceiptOffsetBillPo();
        updatePo.setBillStatus(receiptOffsetBillStatusEnum.getStatusCode());
        ContextUserInfo userInfo = UserContextUtil.getCurrentUser();
        updatePo.setUpdaterId(userInfo.getId());
        updatePo.setUpdaterName(userInfo.getUserName());
        updatePo.setUpdateTime(LocalDateTime.now());

        LambdaQueryWrapper<ReceiptOffsetBillPo> updateWrapper = new LambdaQueryWrapper<>();
        updateWrapper.eq(ReceiptOffsetBillPo::getReceiptOffsetBillId, receiptOffset.getReceiptOffsetBillId());
        updateWrapper.eq(ReceiptOffsetBillPo::getIsDeleted, 0);
        int update = receiptOffsetBillMapper.update(updatePo, updateWrapper);

        if (update <= 0) {
            throw new HMYRuntimeException(msgCode);
        }
    }

    public ReceiptOffsetBillStatusEnum getToBillStatusEnum(ReceiptOffsetAduitDto aduitDto) {
        ReceiptOffsetBillStatusEnum toStatusEnum;

        if (Boolean.TRUE.equals(aduitDto.getPass())) {
            //审批通过
            //当前审批节点
            switch (aduitDto.getApprovalNodeEnum()) {
                case AREA_MANAGER:
                    toStatusEnum = ReceiptOffsetBillStatusEnum.CASHIER_APPROVE_ING;
                    break;
                case CASHIER:
                    toStatusEnum = ReceiptOffsetBillStatusEnum.ARACCOUNTANT_APPROVE_ING;
                    break;
                case ARACCOUNTANT:
                    toStatusEnum = ReceiptOffsetBillStatusEnum.APPROVE_PASS;
                    break;
                default:
                    throw new HMYRuntimeException(506900009);
            }
        } else {
            //审核驳回
            toStatusEnum = ReceiptOffsetBillStatusEnum.APPROVE_REJECTED;
        }

        return toStatusEnum;
    }

    public ReceiptOffsetBillStatusEnum getToRevokeBillStatusEnum(ReceiptOffsetRevokeDto revokeDto) {
        //当前审批节点
        switch (revokeDto.getApprovalNodeEnum()) {
            case AREA_MANAGER:
                checkRevokeStatus(revokeDto, ReceiptOffsetBillStatusEnum.AREA_MANAGER_APPROVE_ING);
                return ReceiptOffsetBillStatusEnum.REVOKE;
            case CASHIER:
                checkRevokeStatus(revokeDto, ReceiptOffsetBillStatusEnum.CASHIER_APPROVE_ING);
                return ReceiptOffsetBillStatusEnum.AREA_MANAGER_APPROVE_ING;
            case ARACCOUNTANT:
                checkRevokeStatus(revokeDto, ReceiptOffsetBillStatusEnum.ARACCOUNTANT_APPROVE_ING);
                return ReceiptOffsetBillStatusEnum.CASHIER_APPROVE_ING;
            default:
                throw new HMYRuntimeException(506900009);
        }
    }

    private void checkRevokeStatus(ReceiptOffsetRevokeDto revokeDto, ReceiptOffsetBillStatusEnum checkStatusEnum) {
        if (!revokeDto.getReceiptOffsetBillPo().getBillStatus().equals(checkStatusEnum.getStatusCode())) {
            throw new HMYRuntimeException(506900003);
        }
    }

}
